
var controller = new ( function() {

	/**
	* @private
	* @class
	* @final
	* Класс содержащий характеристики браузера
	* @memberOf  controller
	*/
	var browser = new ( function() {

		//--------------------------------------------------------------------------
		//
		//  Class variables
		//
		//--------------------------------------------------------------------------

		/**
		* @private
		*/
		var _u = navigator.userAgent,

		_msie =   0,
		_opera =  0,
		_gecko =  0,
		_webkit = 0,

		m;

		m = _u.match( /AppleWebKit\/([\.\d]*)/ );
		if ( m ) {
			if ( m[1] ) _webkit = parseFloat( m[1] );
			else    _webkit = 1;
		} else if ( ( /KHTML/ ).test( _u ) ) {
			_webkit = 1;
		} else {
			m = _u.match( /Opera[\s\/]([^\s]*)/ );
			if ( m ) {
				if ( m[1] ) _opera = parseFloat( m[1] );
				else    _opera = 1;
			} else {
				m = _u.match( /MSIE\s([^;]*)/ );
				if ( m ) {
					if ( m[1] ) _msie = parseFloat( m[1] );
					else    _msie = 1;
				} else {
					m = _u.match( /Gecko\/([^\s]*)/ );
					if ( m ) {
						m = _u.match( /rv:([\.\d]*)/ );
						if ( m && m[1] )  _gecko = parseFloat( m[1] );
						else        _gecko = 1;
					}
				}
			}
		}

		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------

		/**
		* @private
		* @constructor
		*/
		var Browser = new Function(),
		BrowserPrototype = Browser.prototype;

		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------

		/**
		* @method
		* получает версию Gecko ( 0 - если не используется )
		* @return  {Number}  версия
		*/
		BrowserPrototype.getGecko = function() {
			return _gecko;
		};

		/**
		* @method
		* получает версию AppleWebKit ( 0 - если не используется )
		* @return  {Number}  версия
		*/
		BrowserPrototype.getWebKit = function() {
			return _webkit;
		};

		/**
		* @method
		* получает версию Internet Explorer ( 0 - если не используется )
		* @return  {Number}  версия
		*/
		BrowserPrototype.getMSIE = function() {
			return _msie;
		};

		/**
		* @method
		* получает версию Opera ( 0 - если не используется )
		* @return  {Number}  версия
		*/
		BrowserPrototype.getOpera = function() {
			return _opera;
		};

		/**
		* @method
		* @return  {String}
		*/
		BrowserPrototype.toString = function() {
			return '[Browser ' +
			' gecko=' +   _gecko +
			' webkit=' +  _webkit +
			' opera=' +   _opera +
			' msie=' +    _msie +
			']';
		};

		return Browser;

	}() );

	
	var win =     window,
      g_win =     win,
      t_win,
      doc =     win.document,
      loc =     win.location,
      t_loc,

      MMath =     Math,

      msie =      browser.getMSIE(),

      _FILENAME =   'controller.js',
      _NOTATION =   /([^^\/])([A-Z])/g,

      _incluedes =  new Object(),
      _files =    new Object(),
      _requires =   new Object(),

      _xhr,
      _root,
      _logging =    /(;|^)\s*\$bl=1\s*(;|$)/.test( doc.cookie );
	// выдёргиваем максимально глобальное окно
    try {
      while ( ( t_win = g_win.parent ) && t_win !== g_win ) {
        t_loc = t_win.location;
        if ( t_loc.protocol == loc.protocol && t_loc.hostname == loc.hostname ) {
          g_win = t_win;
        } else {
          break;
        }
      }
    } catch ( e ) {
    }

    // инитиализируем request
    if ( msie && win.ActiveXObject ) {
      try {
        _xhr = new ActiveXObject( 'Microsoft.XMLHTTP' )
      } catch ( e ) {
      }
    }
    if ( !_xhr && win.XMLHttpRequest ) {
      _xhr = new XMLHttpRequest();
      if ( _xhr.overrideMimeType ) {
        _xhr.overrideMimeType( 'text/plain' ); // fix gecko error
      }
    }

    _incluedes[ _FILENAME ] = true;

    // инитиализируем root
    if ( browser.getGecko() ) {
      try {
        _root = ( new Error() ).stack.split( '\n', 2 )[1].match( new RegExp( '^[\\w\\.]*\\(\\)@(.+?)' + _FILENAME + ':\\d+$' ) )[1];
      } catch ( e ) {
      	
      }
    }
    if ( !_root ) {
      var scripts = doc.getElementsByTagName( 'script' ),
        i,
        l = scripts.length,
        s,
        index;
      for ( i=l-1; i>=0; i-- ) { // скорее всего мы последний добавленный скрипт
        s = scripts[ i ].src;
        if ( s ) {
          index = s.lastIndexOf( _FILENAME );
          if ( index == s.length - _FILENAME.length ) { // мы себя нашли
            _root = s.substring( 0, index );
            break;
          }
        }
      }
    }
    if ( !_root ) _root = '/js/game/';

	/**
	* @private
	* @constructor
	*/
	var Controller = new Function(),
	ControllerPrototype = Controller.prototype;
	ControllerPrototype.browser = browser;
	
	    /**
     * @method
     * @return  {Boolean}
     */
    ControllerPrototype.isLogging = function() {
      return _logging;
    };

    /**
     * @method
     * @param {Boolean} value
     */
    ControllerPrototype.setLogging = function(value) {
      doc.cookie = '$bl=' + ( value ? '1; path=/' : '; expires=' + ( new Date( 0 ) ) );
      return _logging = Boolean( value );
    };

    /**
     * @method
     * @return  {window}
     */
    ControllerPrototype.getTop = function() {
      return g_win;
    };
	
	/**
	* @method
	* наследует один класс от другого
	* @param {Function}  Child класс-ребёнок
	* @param {Function}  Parent  класс-родитель
	*/
	ControllerPrototype.extend = function(Child, Parent) {
		var Proxy = new Function();
		Proxy.prototype = Parent.prototype;
		Child.prototype = new Proxy();
		Child.prototype.constructor = Child;
		Child.superPrototype = Parent.prototype;
	};
	
	 /**
     * @method
     * исполняет код вглобальной области видимости
     * @param {String}  source  код
     * @return  {Object}
     */
    ControllerPrototype.eval = function(source) {
      //return ( new Function( source ) ).call( win );
      if ( msie ) {
        return win.execScript( source );
      } else {
        return win.eval( source ); // FIXME: выдаёт ошибки в gecko
      }
      /*
      // альтернативный вариант не внушающий доверия
      var script = document.createElement( 'script' );
      script.type = 'text/javascript';
      script.innerHTML = source;
      document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
      */
    };

    /**
     * @method
     * синхронно получает содержание файла
     * @param {String}  uri   путь к файлу
     * @return  {String}      содержание файла, или null
     */
    ControllerPrototype.getFileContent = function(uri) {
      var result = _files[ uri ];
      if (result === undefined ) {
        if ( g_win != win && g_win.controller && g_win.controller != this ) {
          result = g_win.controller.getFileContent( uri );
        } else {
          if ( _xhr ) {
            try {
              _xhr.open( 'GET', uri, false );
              _xhr.send( null );
              result = _xhr.responseText || null;
            } catch ( e ) {
            }
          }
        }
        _files[ uri ] = result || null;
      }
      return result;
    };

    /**
     * @method
     * синхронно импортирует файл
     * @param {String}  uri   путь к файлу
     * @throws  {Error}       uri not found
     */
    ControllerPrototype.include = function(uri) {
      if ( _incluedes[ uri ] ) return; // рание был добавлен
      _incluedes[ uri ] = true;
      var content = this.getFileContent( uri );
      if ( typeof content != 'string' ) {
        throw new Error( uri + ' not fount.' );
      }
      this.eval( content );
    };

    /**
     * @method
     * проверяет наличие объекта.
     * при его отсутвии пытается его загрузить.
     * @param {String}  name  имя класса
     * @throws  {Error}       object not initialized
     */
    ControllerPrototype.require = function(name) {
      var asset = _requires[ name ];
      if ( asset === undefined ) {
        var arr = name.split( '.' ),
          o =   win,
          n,
          nn =  '',
          s,
          i,
          l = arr.length;
        asset = true;
        for ( i=0; i<l; i++ ) {
          n = arr[ i ];
          nn = arr.slice( 0, i + 1 ).join( '.' );
          if ( nn in _requires ) {
            asset = _requires[ nn ];
            
          } else {
            if ( asset ) {
              if ( !( n in o ) ) {
                s = arr.slice( 0, i + 1 ).join( '/' ).replace( _NOTATION, '$1_$2' ).toLowerCase() + '.js';
                this.include( _root + s );
                if ( !( n in o ) ) {
                  asset = false;
                }
              }
            }
            _requires[ nn ] = asset;
          }
          if ( asset ) {
            o = o[ n ];
          }
        }
      }
      if ( !asset ){
      	
      	 throw new Error( name + ' non initialized.' );
	  }
    };

    /**
     * @method
     * @param {String}  name
     * @return  {Object}
     */
    ControllerPrototype.createAbstractInstance = function(name) {
      var InstanceClass = new Function();
      InstanceClass.prototype.toString = function() {
        return '[package ' + name + ']';
      };
      return new InstanceClass();
    };

    /**
     * @method
     * @param {String}  prefix
     * @return  {String}
     */
    ControllerPrototype.createUniqID = function(prefix) {
      var id;
      do {
        id = prefix + '_' + Math.round( ( new Date() ).getTime() * Math.random() );
      } while ( doc.getElementById( id ) );
      return id;
    };

    /**
     * @method
     * @return  {String}
     */
    ControllerPrototype.getRoot = function() {
      return _root;
    };

    /**
     * @method
     * @return  {String}
     */
    ControllerPrototype.toString = function() {
      return '[package controller]';
    };

	
	return Controller;
}() );
//
